package org.loong.crypto.model.asn1.sm2;

import java.util.Enumeration;

import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;

/**
 * SM2 envelopedKey.
 * 
 * <pre>
 * SM2EnvelopedKey ::= SEQUENCE {
 *     symAlgID                AlgorithmIdentifier,
 *     symEncryptedKey         SM2Cipher,
 *     sm2PublicKey            SM2PublicKey,
 *     sm2EncryptedPrivateKey  BIT STRING
 * }
 * </pre>
 */
public class SM2EnvelopedKey extends ASN1Object {

    private AlgorithmIdentifier algId;

    private SM2Cipher encryptedKey;

    private SM2PublicKey publicKey;

    private DERBitString encryptedPrivateKey;

    public SM2EnvelopedKey(AlgorithmIdentifier algId, SM2Cipher encryptedKey, SM2PublicKey publicKey, DERBitString encryptedPrivateKey) {
        this.algId = algId;
        this.encryptedKey = encryptedKey;
        this.publicKey = publicKey;
        this.encryptedPrivateKey = encryptedPrivateKey;
    }

    public SM2EnvelopedKey(ASN1Sequence seq) {
        if (seq.size() != 4) {
            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
        }

        Enumeration<?> e = seq.getObjects();
        this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
        this.encryptedKey = SM2Cipher.getInstance(e.nextElement());
        this.publicKey = SM2PublicKey.getInstance(e.nextElement());
        this.encryptedPrivateKey = DERBitString.convert(ASN1BitString.getInstance(e.nextElement()));
    }

    public static SM2EnvelopedKey getInstance(Object obj) {
        if (obj instanceof SM2EnvelopedKey) {
            return ((SM2EnvelopedKey) obj);
        }
        
        if (obj != null) {
            return new SM2EnvelopedKey(ASN1Sequence.getInstance(obj));
        }

        return null;
    }

    public AlgorithmIdentifier getAlgId() {
        return algId;
    }

    public SM2Cipher getEncryptedKey() {
        return encryptedKey;
    }

    public SM2PublicKey getPublicKey() {
        return publicKey;
    }

    public DERBitString getEncryptedPrivateKey() {
        return encryptedPrivateKey;
    }

    @Override
    public ASN1Primitive toASN1Primitive() {
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(algId);
        v.add(encryptedKey);
        
        if (publicKey != null) {
            v.add(publicKey.getPublicKeyData());
        }
        
        v.add(encryptedPrivateKey);
        return new DERSequence(v);
    }
}
